package com.wechat.pay.contrib.apache.httpclient;

import com.wechat.pay.contrib.apache.httpclient.auth.*;

import java.security.cert.X509Certificate;
import java.util.List;

import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.execchain.ClientExecChain;

/**
 * 继承自HttpClientBuilder,可以创建HttpClient对象, 可以使用PoolingHttpClientConnectionManager管理;
 */
public class WechatPayHttpClientBuilder extends HttpClientBuilder {

    /**
     * 凭证处理器, 用来获取凭证, 就是在请求时header需要的签名信息;
     */
    private Credentials credentials;

    /**
     * 验签器, 验证应答是否为微信支付回复, 验签器要用到微信支付平台证书;
     */
    private Validator validator;

    /**
     * 获取系统信息, 用于添加User-Agent头;
     */
    static final String os = System.getProperty("os.name") + "/" + System.getProperty("os.version");

    /**
     * 用于添加User-Agent头;
     */
    static final String version = System.getProperty("java.version");

    private WechatPayHttpClientBuilder() {
        super();
        String userAgent = String.format("WechatPay-Apache-HttpClient/%s (%s) Java/%s", getClass().getPackage().getImplementationVersion(), os, version == null ? "Unknown" : version);
        setUserAgent(userAgent);
    }

    public static WechatPayHttpClientBuilder create() {
        return new WechatPayHttpClientBuilder();
    }

    /**
     * 使用默认的凭证处理器;
     *
     * @param merchantId 商户id
     * @return {@link WechatPayHttpClientBuilder}
     */
    public WechatPayHttpClientBuilder withMerchant(String merchantId, Cert cert) {
        this.credentials = new WechatPay2Credentials(merchantId, new PrivateKeySigner(cert));
        return this;
    }

    /**
     * 可以自定义凭证处理器, 和上面个方法中使用其中一个就行了;
     *
     * @param credentials 凭证处理器;
     * @return {@link WechatPayHttpClientBuilder}
     */
    public WechatPayHttpClientBuilder withCredentials(Credentials credentials) {
        this.credentials = credentials;
        return this;
    }

    /**
     * 添加默认的验签器及Verifier
     *
     * @param certificates 微信支付平台证书
     * @return {@link WechatPayHttpClientBuilder}
     */
    public WechatPayHttpClientBuilder withWechatpay(List<X509Certificate> certificates) {
        this.validator = new WechatPay2Validator(new CertificatesVerifier(certificates));
        return this;
    }

    /**
     * 可自定义验签器, 此工具中还提供了另外一个自动更新平台证书的Verifier, 可以添加那一个实现平台证书的自动更新;
     *
     * @param validator 验签器
     * @return {@link WechatPayHttpClientBuilder}
     */
    public WechatPayHttpClientBuilder withValidator(Validator validator) {
        this.validator = validator;
        return this;
    }

    @Override
    public CloseableHttpClient build() {
        if (credentials == null) {
            throw new IllegalArgumentException("缺少身份认证信息");
        }
        if (validator == null) {
            throw new IllegalArgumentException("缺少签名验证信息");
        }

        return super.build();
    }

    /**
     * 重写了{@link HttpClientBuilder}的方法, 此方法在{@link HttpClientBuilder#build()}中会执行, 执行时会将{@link SignatureExec}添加到执行链中,
     * 在每次请求时及响应都会执行{@link SignatureExec#execute(HttpRoute, HttpRequestWrapper, HttpClientContext, HttpExecutionAware)}方法
     *
     * @param requestExecutor 下级链条执行器;
     * @return 执行器
     */
    @Override
    protected ClientExecChain decorateProtocolExec(final ClientExecChain requestExecutor) {
        return new SignatureExec(this.credentials, this.validator, requestExecutor);
    }
}
